#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

#ifdef _WIN32
#include <iphlpapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#endif

typedef struct {
	char     interfaceName[256];
	uint32_t ipAddress;  // 网络字节序存储
	uint32_t subnetMask; // 网络字节序存储
} NetInfo;

// 仅支持IPv4，非线程安全
const char *ipToStr(uint32_t ip) {
	struct in_addr addr;
	addr.s_addr = ip;
	return inet_ntoa(addr); // 注意：非线程安全
}

// inet_ntop: 支持IPv6, 线程安全
const char *ipToStrSafe(uint32_t ip, char *buffer, size_t bufferSize) {
	struct in_addr addr;
	addr.s_addr = ip;
	return inet_ntop(AF_INET, &addr, buffer, bufferSize);
}

// 过滤无效地址

bool isValidAddress(uint32_t ip) {
	// 转换为本地字节序便于位操作
	uint32_t host_ip = ntohl(ip);
	// 过滤 0.0.0.0
	if (host_ip == 0x00000000) return false;
	// 过滤 255.255.255.255（广播地址）
	if (host_ip == 0xFFFFFFFF) return false;
	// 过滤 127.0.0.0/8（本地回环地址）
	if ((host_ip & 0xFF000000) == 0x7F000000) return false;
	// 过滤 224.0.0.0 ~ 239.255.255.255（组播地址）
	if ((host_ip & 0xF0000000) == 0xE0000000) return false;
	return true;
}

int getSubnetMasks(NetInfo **results, int *count) {
	*count   = 0;
	*results = nullptr;

#ifdef _WIN32
	ULONG size = 0;
	if (GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &size) != ERROR_BUFFER_OVERFLOW) {
		return -1;
	}

	PIP_ADAPTER_ADDRESSES adapter = (PIP_ADAPTER_ADDRESSES) malloc(size);
	if (!adapter) return -1;

	DWORD ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter, &size);
	if (ret != ERROR_SUCCESS) {
		free(adapter);
		return -1;
	}

	// 计算有效接口数量
	int needed = 0;
	for (PIP_ADAPTER_ADDRESSES ptr = adapter; ptr; ptr = ptr->Next) {
		if (ptr->OperStatus == IfOperStatusUp) {
			needed += ptr->FirstUnicastAddress ? 1 : 0;
		}
	}

	if (needed == 0) {
		free(adapter);
		return 0;
	}

	*results = (NetInfo *) malloc(needed * sizeof(NetInfo));
	if (!*results) {
		free(adapter);
		return -1;
	}

	int index = 0;
	for (PIP_ADAPTER_ADDRESSES ptr = adapter; ptr; ptr = ptr->Next) {
		if (ptr->OperStatus != IfOperStatusUp) continue;

		for (PIP_ADAPTER_UNICAST_ADDRESS ua = ptr->FirstUnicastAddress; ua; ua = ua->Next) {
			if (ua->Address.lpSockaddr->sa_family != AF_INET) continue;

			sockaddr_in *addr_in = (sockaddr_in *) ua->Address.lpSockaddr;
			if (!isValidAddress(addr_in->sin_addr.s_addr) continue;

			// 获取IP地址
			sockaddr_in *addr_in        = (sockaddr_in *) ua->Address.lpSockaddr;
			(*results)[index].ipAddress = addr_in->sin_addr.s_addr;

			// 计算子网掩码
			uint32_t prefix              = ua->OnLinkPrefixLength > 32 ? 32 : ua->OnLinkPrefixLength;
			uint32_t mask                = htonl((0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF);
			(*results)[index].subnetMask = mask;

			// 拷贝接口名称
			strncpy((*results)[index].interfaceName, ptr->FriendlyName, sizeof((*results)[index].interfaceName) - 1);
			(*results)[index].interfaceName[sizeof((*results)[index].interfaceName) - 1] = '\0';

			index++;
		}
	}

	*count = index;
	free(adapter);

#else // Linux实现
	struct ifaddrs *ifaddr = nullptr;
	if (getifaddrs(&ifaddr) == -1) {
		return -1;
	}

	int needed = 0;
	for (struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET && ifa->ifa_netmask) {
			needed++;
		}
	}

	if (needed == 0) {
		freeifaddrs(ifaddr);
		return 0;
	}

	*results = (NetInfo *) malloc(needed * sizeof(NetInfo));
	if (!*results) {
		freeifaddrs(ifaddr);
		return -1;
	}

	int index = 0;
	for (struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
		if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET || !ifa->ifa_netmask) continue;

		// 获取IP地址
		sockaddr_in *addr           = (sockaddr_in *) ifa->ifa_addr;
		(*results)[index].ipAddress = addr->sin_addr.s_addr;
		if (!isValidAddress(addr->sin_addr.s_addr)) continue;

		// 获取子网掩码
		sockaddr_in *mask            = (sockaddr_in *) ifa->ifa_netmask;
		(*results)[index].subnetMask = mask->sin_addr.s_addr;

		// 拷贝接口名称
		strncpy((*results)[index].interfaceName, ifa->ifa_name, sizeof((*results)[index].interfaceName) - 1);
		(*results)[index].interfaceName[sizeof((*results)[index].interfaceName) - 1] = '\0';

		index++;
	}

	*count = index;
	freeifaddrs(ifaddr);
#endif

	return 0;
}

void freeNetInfoArray(NetInfo *array) { free(array); }

bool isSameSubnet(uint32_t ip1, uint32_t ip2, uint32_t mask) { return (ip1 & mask) == (ip2 & mask); }


// g++ -std=c++11 -o subnet.exe subnet.cpp
int main() {
	NetInfo *info  = nullptr;
	int      count = 0;

	if (getSubnetMasks(&info, &count) == 0) {
		for (int i = 0; i < count; ++i) {
			// std::cout << "Interface: " << info[i].interfaceName << "\n"
			//           << "IP: " << ipToStr(info[i].ipAddress) << "\n"
			//           << "Mask: " << ipToStr(info[i].subnetMask) << "\n"
			//           << "----------------\n";

			//   使用ipToStrSafe函数
			char ipStr[INET_ADDRSTRLEN];
			char maskStr[INET_ADDRSTRLEN];
			std::cout << "Interface: " << info[i].interfaceName << "\n"
			          << "IP: " << ipToStrSafe(info[i].ipAddress, ipStr, sizeof(ipStr)) << "\n"
			          << "Mask: " << ipToStrSafe(info[i].subnetMask, maskStr, sizeof(maskStr)) << "\n"
			          << "----------------\n";
		}
		freeNetInfoArray(info);
	}

	// 测试子网判断
	uint32_t ip1  = inet_addr("192.168.1.100");
	uint32_t ip2  = inet_addr("192.168.1.200");
	uint32_t mask = inet_addr("255.255.255.0");
	std::cout << "Same subnet: " << (isSameSubnet(ip1, ip2, mask) ? "Yes" : "No") << std::endl;
	return 0;
}
